package com.rxz.utils;

import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class SimpleRedisLock implements ILock{

    private String name;
    private StringRedisTemplate stringRedisTemplate;
    public SimpleRedisLock(String name,StringRedisTemplate stringRedisTemplate){
        this.name=name;
        this.stringRedisTemplate=stringRedisTemplate;
    }

    private static final String KEY_PREFIX="lock:";
    private static final String ID_PREFIX= UUID.randomUUID().toString()+"-";
    private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;
    static {
        UNLOCK_SCRIPT=new DefaultRedisScript<>();
        UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));
        UNLOCK_SCRIPT.setResultType(Long.class);
    }//初始化脚本

    @Override
    public boolean tryLock(long timeoutSec) {

        String threadId =ID_PREFIX + Thread.currentThread().getId();
        Boolean success = stringRedisTemplate.opsForValue()
                .setIfAbsent(KEY_PREFIX + name, threadId , timeoutSec, TimeUnit.SECONDS);
        String syc = stringRedisTemplate.opsForValue().get("syc");
        Boolean hasKey = stringRedisTemplate.hasKey("syc");
        System.out.println("hasKey是："+hasKey);
        System.out.println("name是：" + name);
        System.out.println("syc是：" + syc);
        if (name.equals(syc) && hasKey){
            return false;
        }
        System.out.println("success是：" +success);
        return Boolean.TRUE.equals(success);
        //若直接返回Boolean类型的success将会进行拆箱，将会有安全风险
    }

    //使用lua脚本来让释放锁具备原子性
    @Override
    public void unlock() {
        //加载lua脚本
        stringRedisTemplate.execute(
                UNLOCK_SCRIPT,
                Collections.singletonList(KEY_PREFIX + name),//当前锁的名称，传入脚本中，拿到锁中的线程id
                ID_PREFIX+ Thread.currentThread().getId()//当前线程id
        );
    }

//原 不具备原子性的释放锁操作
    /*@Override
    public void unlock() {
        //获取当前线程id
        String threadId =ID_PREFIX+ Thread.currentThread().getId();
        //获取当前锁中的线程id
        String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + name);
        //判断当前线程id是否与当前锁的中存放的线程id一致
        if(threadId.equals(id)){
            //释放
            stringRedisTemplate.delete(KEY_PREFIX+name);
        }
    }*/
}
